//
//  NetworkTool.swift
//  NetworkTool
//
//  Created by Ben on 2021/9/7.
//

import Foundation
import Combine
import Alamofire
import SwiftUI

enum APIError: Error {
    case custom(msg: String)
}

struct NetworkTool {
    
    
    /// 请求站外api
    /// - Returns: 返回请求结果
    static func uploadImageToSMMS(image: UIImage) async throws -> UploadToSMMSResultModel {
        
        
        try await withUnsafeThrowingContinuation({ continuation in
            
            guard let resizeImage = image.sd_resizedImage(with: CGSize(width: 240, height: 240), scaleMode: .aspectFill) else {
                
                continuation.resume(throwing: APIError.custom(msg: "图片压缩失败"))
                return
            }
            
            let fileName = "\(Int(Date().timeIntervalSince1970 * 1000)).jpg"
            
            let url = "https://sm.ms/api/v2/upload"
            let headers = HTTPHeaders(["Content-Type": "multipart/form-data", "Authorization": Configs.SMMS_TOKEN])
            
            AF.upload(multipartFormData: { multipartFormData in
                multipartFormData.append(resizeImage.jpegData(compressionQuality: 1)!, withName: "smfile", fileName: fileName, mimeType: "image/jpg")
            }, to: url, method: .post, headers: headers)
                .uploadProgress(queue: .main, closure: { progress in
                        Dlog("Upload Progress: \(progress.fractionCompleted)")
                        
                        
                    })
                .responseJSON(completionHandler: { response in
                    switch response.result {
                    case let .success(data):
                        Dlog(data)
                    case let .failure(error):
                        Dlog(error)
                    }
                })
                .responseData(completionHandler: { response in
                    switch response.result {
                    case let .success(data):
                        
                        do {
                            let model = try JSONDecoder().decode(UploadToSMMSResultModel.self, from: data)
                            
                            if model.data == nil {
                                continuation.resume(throwing: APIError.custom(msg: "上传失败"))
                                return
                            }
                            continuation.resume(returning: model)
                        } catch {
                            continuation.resume(throwing: APIError.custom(msg: error.localizedDescription))
                        }
                    case let .failure(error):
                        continuation.resume(throwing: APIError.custom(msg: error.localizedDescription))
                        
                    }
                })
                
                
        })
    }
    
    static func awaitRequest<T, V>(request: T, responseType: V.Type) async throws -> NetworkBaseModel<V> where T: BaseRequestProtocol, V: Codable {
        
        try await withUnsafeThrowingContinuation({ continuation in
            let api = AF.request(request)
                .validate(statusCode: 200 ..< 300)
                .validate(contentType: [NetworkConfig.contentType])
                .cURLDescription { text in
                    Dlog("\n=========请求接口的详细信息=========")
                    Dlog("api: \(request.urlRequest?.url?.absoluteString ?? "")")
                    Dlog("params: \(request.parameters ?? [:])")
                    
                }
                .responseData { response in
                    switch response.result {
                    case let .success(data):
                        
                        
                        do {
                        
                            let model = try JSONDecoder().decode(NetworkBaseModel<V>.self
                                                      , from: data)
                            
                            // 拦截错误，抛出异常
                            if model.code == 0 {
                                continuation.resume(throwing: APIError.custom(msg: model.message ?? "未知错误"))
                                return
                            }
                            
                            continuation.resume(returning: model)
                        } catch {
                            
//                            promise(.failure(APIError.custom(msg: error.localizedDescription)))
                            continuation.resume(throwing: error)
                        }
                        
                    case let .failure(error):
                        
//                        promise(.failure(APIError.custom(msg: error.localizedDescription)))
                        continuation.resume(throwing: error)

                    }
                }
                        
            api.resume()
        })
    }
    static func publishRequest<T, V>(request: T, responseType: V.Type) -> Future<NetworkBaseModel<V>, APIError> where T: BaseRequestProtocol, V: Codable {
        return Future { promise in
            
            
            let api = AF.request(request)
                .validate(statusCode: 200 ..< 300)
                .validate(contentType: [NetworkConfig.contentType])
                .cURLDescription { text in
                    Dlog(text)
                }
                .responseData { response in
                    switch response.result {
                    case let .success(data):
                        Dlog(data)
                        do {
                        
                        let model = try JSONDecoder().decode(NetworkBaseModel<V>.self
                                                      , from: data)
                            
                            promise(.success(model))
                        } catch {
                            
                            promise(.failure(APIError.custom(msg: error.localizedDescription)))
                        }
                        
                    case let .failure(error):
                        
                        promise(.failure(APIError.custom(msg: error.localizedDescription)))

                    }
                }
                        
            api.resume()
        }
    }
}
